#include "EventbasePool.h"

EventbasePool::EventbasePool()
    : nextPool_(0)
{
}

EventbasePool::~EventbasePool()
{
}

void EventbasePool::start(int size)
{
    started_ = true;
    if (size <= 0)
    {
        throw std::invalid_argument("size must be greater than 0");
    }
    for (int i = 0; i < size; ++i)
    {
        workThreads_.emplace_back(std::make_unique<std::thread>(
            [&]()
            {
                event_base *base;
                {
                    std::lock_guard<std::mutex> lock(mutex_);
                    base = event_base_new();
                    eventbasePool_.emplace_back(std::shared_ptr<event_base>(base, event_base_free));
                }
                //while (started_) {
                int res = event_base_loop(base, EVLOOP_NO_EXIT_ON_EMPTY);
                if (res == 0)
                {
                    std::cerr << "event_base_loop exited normally" << std::endl;
                }
                else
                {
                    std::cerr << "event_base_loop exited with error: " << strerror(errno) << std::endl;
                }
                //}
            }));
    }
}

void EventbasePool::stop()
{
    started_ = false;
    std::lock_guard<std::mutex> lock(mutex_);
    for (auto &base : eventbasePool_)
    {
        event_base_once(base.get(), -1, EV_TIMEOUT, [](evutil_socket_t, short, void* arg) {
            event_base* base = reinterpret_cast<event_base*>(arg);
            event_base_loopexit(base, nullptr);
            },
            base.get(), nullptr);
    }

    for (auto &thread : workThreads_)
    {
        if (thread && thread->joinable())
        {
            thread->join();
        }
    }
}

std::shared_ptr<event_base> EventbasePool::getNextBase()
{
    std::lock_guard<std::mutex> lock(mutex_);
    nextPool_ %= eventbasePool_.size();
    return eventbasePool_[nextPool_++];
}
